Skip to content

azurerm_nat_gateway/azurerm_public_ip/azurerm_public_ip_prefix - support for new SKU StandardV2#31197

Merged
sreallymatt merged 20 commits intohashicorp:mainfrom
neil-yechenwei:networkskuv2
Mar 27, 2026
Merged

azurerm_nat_gateway/azurerm_public_ip/azurerm_public_ip_prefix - support for new SKU StandardV2#31197
sreallymatt merged 20 commits intohashicorp:mainfrom
neil-yechenwei:networkskuv2

Conversation

@neil-yechenwei
Copy link
Copy Markdown
Contributor

@neil-yechenwei neil-yechenwei commented Nov 26, 2025

Community Note

  • Please vote on this PR by adding a 👍 reaction to the original PR to help the community and maintainers prioritize for review
  • Please do not leave comments along the lines of "+1", "me too" or "any updates", they generate extra noise for PR followers and do not help prioritize for review

Description

This PR is to support for new SKU "StandardV2".

PR Checklist

  • I have followed the guidelines in our Contributing Documentation.
  • I have checked to ensure there aren't other open Pull Requests for the same update/change.
  • I have checked if my changes close any open issues. If so please include appropriate closing keywords below.
  • I have updated/added Documentation as required written in a helpful and kind way to assist users that may be unfamiliar with the resource / data source.
  • I have used a meaningful PR title to help maintainers and other users understand this change and help prevent duplicate work.
    For example: “resource_name_here - description of change e.g. adding property new_property_name_here

Changes to existing Resource / Data Source

  • I have added an explanation of what my changes do and why I'd like you to include them (This may be covered by linking to an issue above, but may benefit from additional explanation).
  • I have written new tests for my resource or datasource changes & updated any relevant documentation.
  • I have successfully run tests with my changes locally. If not, please provide details on testing challenges that prevented you running the tests.
  • (For changes that include a state migration only). I have manually tested the migration path between relevant versions of the provider.

Testing

  • My submission includes Test coverage as described in the Contribution Guide and the tests pass. (if this is not possible for any reason, please include details of why you did or could not add test coverage)
image image

Change Log

Below please provide what should go into the changelog (if anything) conforming to the Changelog Format documented here.

  • azurerm_nat_gateway/azurerm_public_ip/azurerm_public_ip_prefix - support for new SKU StandardV2

This is a (please select all that apply):

  • Bug Fix
  • New Feature (ie adding a service, resource, or data source)
  • Enhancement
  • Breaking Change

Related Issue(s)

Fixes # 0000

AI Assistance Disclosure

  • AI Assisted - This contribution was made by, or with the assistance of, AI/LLMs

Rollback Plan

If a change needs to be reverted, we will publish an updated version of the provider.

Changes to Security Controls

Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.

Note

If this PR changes meaningfully during the course of review please update the title and description as required.

@teowa
Copy link
Copy Markdown
Collaborator

teowa commented Nov 27, 2025

Thanks @neil-yechenwei , LGTM!

@fabiendelpierre
Copy link
Copy Markdown

FYI it looks like #30957 is working on the same thing.

Copy link
Copy Markdown
Collaborator

@gerrytan gerrytan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @neil-yechenwei , I left some comments to address.

Also can you please rerun the acctest, I saw there were typos into the test prefix so some tests are not picked up.

location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
sku_name = "StandardV2"
zones = ["1", "2", "3"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is specifying all zones required for StandardV2? If so please add a CustomizeDiff validator for this.

Refer to:

StandardV2 NAT Gateway is zone-redundant, meaning that it provides outbound connectivity from all zones in a region instead of a single zone like Standard NAT Gateway.

https://learn.microsoft.com/en-us/azure/nat-gateway/nat-overview

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reason1: I think we should not use a CustomizeDiff validator to force users to specify zones, because the API also allows it when users do not specify them.

Reason2: About ignoring zones, according to the previous recommendations provided by HC, when the configuration of property A affects other properties—for example, property B—the affected property B should be handled by the user in the Terraform configuration. This allows users to clearly understand that when property A is modified, property B will also be impacted, rather than suppressing the issue through changes in the provider, which could cause property B to change without the user being aware of it. This can prevent users from encountering unexpected behavior. So, I add the comment for it.

Comment thread internal/services/network/public_ip_resource.go
@neil-yechenwei
Copy link
Copy Markdown
Contributor Author

@gerrytan , thanks for the comments. Please take another look.

Copy link
Copy Markdown
Collaborator

@gerrytan gerrytan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @neil-yechenwei , we still need to implement a CustomizeDiff validator to avoid user from seeing unexpected plan diff.

My understanding is if NAT gateway SKU is StandardV2, and zones are not set, the backend will set it to [1,2,3] right?

* `sku_name` - (Optional) The SKU which should be used. At this time the only supported value is `Standard`. Defaults to `Standard`.
* `sku_name` - (Optional) The SKU which should be used. Possible values are `Standard` and `StandardV2`. Defaults to `Standard`.

-> **Note:** When `StandardV2` is enabled, service API will also enable `zones`. The user has to explicitly set this property in the Terraform configuration or handle it using `ignore_changes`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please implement a CustomizeDiff validation to force user to set zones to [1, 2 ,3] if StandardV2 SKU is used. A documentation note like this is not enough as user can miss it.

Also please reword this sentence to: 'StandardV2' SKU require zones to be set to [1,2,3], see [MS learn documentation](link to relevant doc) for more info

Copy link
Copy Markdown
Contributor Author

@neil-yechenwei neil-yechenwei Dec 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added CustomizeDiff validation and updated the md file. Thanks.

@gerrytan
Copy link
Copy Markdown
Collaborator

gerrytan commented Dec 7, 2025

Also please rerun acctest against latest commit hash, with typos on the test prefix variable fixed.

@neil-yechenwei
Copy link
Copy Markdown
Contributor Author

neil-yechenwei commented Dec 8, 2025

@gerrytan , thanks for the comments. I updated PR. Please take another look. I also rerun acctest.

image

Copy link
Copy Markdown
Collaborator

@gerrytan gerrytan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @neil-yechenwei , I left 2 minor touch up comments to address and this should be good to go.

As discussed privately over DM, asking using to use ignore_changes will result in poor user experience / confusion. Although we can use optional + computed, but historically it is more prone to bugs, so thank you for implementing the CustomizeDiff validation instead.

sort.Strings(zones)

requiredZones := []string{"1", "2", "3"}
if len(zones) != 3 || zones[0] != "1" || zones[1] != "2" || zones[2] != "3" {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplified using slices.Equal(zones, []string{"1", "2", "3"})

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

Comment thread internal/services/network/nat_gateway_resource_test.go
@WodansSon
Copy link
Copy Markdown
Collaborator

@teowa, I was looking at the PR I noticed there are two association resources that only append IDs to the NAT gateway model and never verify SKU compatibility. Microsoft’s NAT Gateway docs state that StandardV2 NAT gateways require StandardV2 public IP addresses or prefixes. With the current code, a config like StandardV2 NAT + Standard public IP will plan cleanly and fail only when Azure rejects the update. Since we are not allowed to do GET calls during the plan phase, I think the best we can do is to add a note to each of the association resources documentation page, WDYT?

@github-actions github-actions Bot added size/XL and removed size/L labels Mar 10, 2026
Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@teowa, thanks for pushing those changes, I notice one minor nit in the docs and I also left one question. If you can get those taken care of, I think we can move this PR along.

Current Status: Requested Changes

Comment thread website/docs/r/public_ip.html.markdown Outdated
* `reverse_fqdn` - (Optional) A fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN.

* `sku` - (Optional) The SKU of the Public IP. Accepted values are `Basic` and `Standard`. Defaults to `Standard`. Changing this forces a new resource to be created.
* `sku` - (Optional) The SKU of the Public IP. Possible values are `Basic`, `Standard`, and `StandardV2`. Defaults to `Standard`. Changing this forces a new Public IP to be created.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update this to use the standard wording per the contributor guidelines.

Suggested change
* `sku` - (Optional) The SKU of the Public IP. Possible values are `Basic`, `Standard`, and `StandardV2`. Defaults to `Standard`. Changing this forces a new Public IP to be created.
* `sku` - (Optional) The SKU of the Public IP. Possible values are `Basic`, `Standard`, and `StandardV2`. Defaults to `Standard`. Changing this forces a new resource to be created.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment thread website/docs/r/public_ip.html.markdown Outdated
* `sku_tier` - (Optional) The SKU Tier that should be used for the Public IP. Possible values are `Regional` and `Global`. Defaults to `Regional`. Changing this forces a new resource to be created.

-> **Note:** When `sku_tier` is set to `Global`, `sku` must be set to `Standard`.
-> **Note:** When `sku_tier` is set to `Global`, `sku` must be set to `Standard` or `StandardV2`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? I thought the documentation said this had to be Standard.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By tests, StandardV2 can also set with Global sku_tier. Actually it should be
-> Note: When sku_tier is set to Global, sku cannot be Basic

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @teowa this is a good catch. We don't actually support Global tier on V2 IPs. We will add a validation from our side to block this. Only Standard SKU IPs support Global tier.

@teowa
Copy link
Copy Markdown
Collaborator

teowa commented Mar 11, 2026

Hi @WodansSon , thanks for reviewing this! I've updated the code, please take another look!
Test (the one failure is because the quota limit of 20 public IPs per region within the subscription has been reached):
image

WodansSon
WodansSon previously approved these changes Mar 12, 2026
Copy link
Copy Markdown
Collaborator

@WodansSon WodansSon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@teowa, thanks for pushing those changes, this LGTM now! 🚀

Copy link
Copy Markdown
Collaborator

@sreallymatt sreallymatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @neil-yechenwei / @teowa - I've left some comments inline.

Additionally, would you be able to get clarification from the service team regarding the actual retirement date? Currently all of our tests provisioning Basic public IP resources are passing.

"1",
"2",
"3",
}, false),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should start limiting input to zone/zones arguments. There is at least one region that supports 4 (eastus2euap, while a bit of a special case, users could be using it)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated; now we just check that it isn't an empty string.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from PG here - new creates of Basic SKU public IP resources as of March 2025 deprecation date is not supported. We are working on blocking in NRP, just hasn't rolled out yet.

Comment thread internal/services/network/nat_gateway_resource_test.go
pluginsdk.CustomizeDiffShim(func(_ context.Context, d *pluginsdk.ResourceDiff, _ interface{}) error {
if !isPublicIPBasicSkuDeprecatedForCreation() {
return nil
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused as to why this function is here, isPublicIPBasicSkuDeprecatedForCreation() is already true so there's no need for it?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, this is removed.

}
}

const publicIPBasicSkuCreateDeprecationMessage = "creation of new `Basic` SKU public IP addresses is no longer permitted following its deprecation on March 31, 2025. This also affects `allocation_method` set to `Dynamic`, as it is only available with the `Basic` SKU. Existing `Basic` SKU public IP addresses can continue to be used until September 30, 2025. For more information, see https://azure.microsoft.com/updates/upgrade-to-standard-sku-public-ip-addresses-in-azure-by-30-september-2025-basic-sku-will-be-retired/"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this part is relevant given this date has passed

Existing Basic SKU public IP addresses can continue to be used until September 30, 2025.

Suggested change
const publicIPBasicSkuCreateDeprecationMessage = "creation of new `Basic` SKU public IP addresses is no longer permitted following its deprecation on March 31, 2025. This also affects `allocation_method` set to `Dynamic`, as it is only available with the `Basic` SKU. Existing `Basic` SKU public IP addresses can continue to be used until September 30, 2025. For more information, see https://azure.microsoft.com/updates/upgrade-to-standard-sku-public-ip-addresses-in-azure-by-30-september-2025-basic-sku-will-be-retired/"
const publicIPBasicSkuCreateDeprecationMessage = "creation of new `Basic` SKU public IP addresses is no longer permitted following its deprecation on March 31, 2025. This also affects `allocation_method` set to `Dynamic`, as it is only available with the `Basic` SKU. For more information, see https://azure.microsoft.com/updates/upgrade-to-standard-sku-public-ip-addresses-in-azure-by-30-september-2025-basic-sku-will-be-retired/"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 239 to 242
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this also applies to StandardV2 so this check needs updating

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, allocation_method must be set to Static when sku is set to Standard or StandardV2

losAngelesLocation = time.UTC
}

deprecationTime := time.Date(2025, time.April, 1, 0, 0, 0, 0, losAngelesLocation)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This date is in the past, so all the tests using this function are already irrelevant? (though they are still passing now)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite being past the deprecation date, it is still possible to allocate a Basic SKU public IP.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, all tests that use sku=Basic for azurerm_public_ip will need to be migrated. These are being addressed in PR #31885.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite being past the deprecation date, it is still possible to allocate a Basic SKU public IP.

new creates of Basic SKU public IP resources as of March 2025 deprecation date is not supported. Azure service team is working on blocking in NRP, just hasn't rolled out yet.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the tests aren't failing yet and the function will always return true, can you remove this in favour of the migration in #31885?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, this is removed now

-> **Note:** Only one Availability Zone can be defined. For more information, please check out the [Azure documentation](https://learn.microsoft.com/en-us/azure/nat-gateway/nat-overview#availability-zones)
-> **Note:** For `Standard`, `zones` may be omitted for a no-zone deployment or set to a single Availability Zone. For more information, please see the [Azure documentation](https://learn.microsoft.com/azure/nat-gateway/nat-overview#availability-zones).

~> **Note:** For `StandardV2`, `zones` should usually be omitted. `StandardV2` NAT Gateway is zone-redundant by default, and Azure may return `zones` as `1`, `2`, and `3` in state even when `zones` is not specified, see [MS learn documentation](https://learn.microsoft.com/azure/nat-gateway/nat-overview#standardv2-nat-gateway) for more info.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor rephrasing that may make it more clear, WDYT?

Suggested change
~> **Note:** For `StandardV2`, `zones` should usually be omitted. `StandardV2` NAT Gateway is zone-redundant by default, and Azure may return `zones` as `1`, `2`, and `3` in state even when `zones` is not specified, see [MS learn documentation](https://learn.microsoft.com/azure/nat-gateway/nat-overview#standardv2-nat-gateway) for more info.
~> **Note:** For `StandardV2`, it is recommend to omit `zones`. The `StandardV2` NAT Gateway is zone-redundant by default, and Azure returns all available `zones` which may differ from the zones specified in config, see [MS learn documentation](https://learn.microsoft.com/azure/nat-gateway/nat-overview#standardv2-nat-gateway) for more info.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment thread website/docs/r/public_ip.html.markdown Outdated

-> **Note:** Public IP Standard SKUs require `allocation_method` to be set to `Static`.

!> **Note:** **On 30 September 2025, `Basic` SKU public IP addresses will be retired in Azure.** You can continue to use your existing `Basic` SKU public IP addresses until then, however, you will no longer be able to create new ones after 31 March 2025. Please see the Azure Update [retirement notification](https://azure.microsoft.com/updates/upgrade-to-standard-sku-public-ip-addresses-in-azure-by-30-september-2025-basic-sku-will-be-retired/) for more information.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Date already passed? This would probably make more sense as something like `sku` can no longer be set to `Basic` as of <date> for new resources"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment thread website/docs/r/public_ip.html.markdown Outdated
* `sku_tier` - (Optional) The SKU Tier that should be used for the Public IP. Possible values are `Regional` and `Global`. Defaults to `Regional`. Changing this forces a new resource to be created.

-> **Note:** When `sku_tier` is set to `Global`, `sku` must be set to `Standard`.
-> **Note:** When `sku_tier` is set to `Global`, `sku` cannot be `Basic`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be validated for?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, When sku_tier is set to Global, sku must be set to Standard.

@teowa
Copy link
Copy Markdown
Collaborator

teowa commented Mar 16, 2026

Hi @sreallymatt , thanks for reviewing this, I've updated the code, please kindly take another look.

@es-cs1
Copy link
Copy Markdown

es-cs1 commented Mar 19, 2026

This will be very much appreciated now that microsoft is deprecating default outbound access on VMs

Type: schema.TypeSet,
Optional: true,
// NOTE: O+C Azure may return availability zones from the API when not specified by the user
Computed: true,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this O+C breaks the existing behaviour of replacing the resource when a user removes zones from their deployment (when sku is Standard). We should try to keep this behaviour intact and we could use a DiffSuppressFunc instead.

Additionally, O+C doesn't entirely resolve the zones diff, currently a user could specify zones for StandardV2 in config (e.g. zones = ["1"]) which would lead to a perpetual diff, we should prevent users from setting zones on StandardV2 with a CustomizeDiff

e.g.

DiffSuppress:

		DiffSuppressOnRefresh: true,
			DiffSuppressFunc: func(_, _, _ string, d *schema.ResourceData) bool {
				// when `sku_name` is `StandardV2`, Azure automatically spreads the deployment across all zones in the region
				return d.Get("sku_name").(string) == string(natgateways.NatGatewaySkuNameStandardVTwo)
			},

CustomizeDiff:

		CustomizeDiff: func(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error {
			if diff.Get("sku_name").(string) == string(natgateways.NatGatewaySkuNameStandardVTwo) {
				if !diff.GetRawConfig().AsValueMap()["zones"].IsNull() {
					return fmt.Errorf("%s resources with `sku_name` set to `%s` are zone-redundant by default, Azure automatically deploys across all available zones. The `zones` argument must be omitted", natGatewayResourceName, natgateways.NatGatewaySkuNameStandardVTwo)
				}
			}

			return nil
		},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense, code updated.

losAngelesLocation = time.UTC
}

deprecationTime := time.Date(2025, time.April, 1, 0, 0, 0, 0, losAngelesLocation)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the tests aren't failing yet and the function will always return true, can you remove this in favour of the migration in #31885?

@teowa
Copy link
Copy Markdown
Collaborator

teowa commented Mar 25, 2026

Hi @sreallymatt , I've updated the code, please take another look. Thanks.

Copy link
Copy Markdown
Collaborator

@sreallymatt sreallymatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @teowa - LGTM ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.